<?php
/**
 * Text analyzer
 *
 * PHP version 5
 *
 * @category   Web
 * @package    Data2People
 * @subpackage Controllers
 * @author     Mike Bevz <mike.bevz@data2people>
 * @copyright  2007-2008 (c) Mike Bevz
 * @license    The BSD License http://data2people.com/license.txt
 * @version    SVN: $Id: Analyzer.php 18 2008-12-03 06:46:09Z michael.bevz $
 *
 *
 */

/**
 * Includes
 */


/**
 * Default controller
 *
 * PHP version 5
 *
 * @category   Web
 * @package    Data2People
 * @subpackage Controllers
 * @author     Mike Bevz <mike.bevz@data2people>
 * @copyright  2007-2008 (c) Mike Bevz
 * @license    The BSD License http://data2people.com/license.txt
 * @version    SVN: $Id: Analyzer.php 18 2008-12-03 06:46:09Z michael.bevz $
 *
 *
 */

class TV_Text_Analyzer
{
    private $_stopWords = array(
    'I', 'a', 'about','an','are','as','at','be','by','com','de','en','for','from','how',
    'in', 'is','it','la','of','on','or','that','the','this','to','was','what','when','where',
    'who', 'will','with','und','the','www' );

    private $_shortWords = array(
    "can't", "you're", "you've", "don't", "it's"
    );
    
    private $_longWords = array(
    "cannot", "you are", "you have", "do not", "it is"
    );
    
    private $_badChars  = array(
        "\xc2", // prefix 1
        "\x80", // prefix 2
        "\x98", // single quote opening
        "\x99", // single quote closing
        "\x8c", // double quote opening
        "\x9d",  // double quote closing,
        'â€œ',  // left side double smart quote
        'â€',  // right side double smart quote
        'â€˜',  // left side single smart quote
        'â€™',  // right side single smart quote
        'â€¦',  // elipsis
        'â€”',  // em dash
        'â€“'  // en dash
    );
    
    private $_goodChars = array('', '', '\'', '\'', '"', '"',
                                '"', '"', "'", "'", "...", "-", "-");

    /**
     * Returns number of words in the given text
     *
     * @param string $text
     *
     * @return int
     * @throws TV_Text_Exception If $text is not string
     */
    public function wordCount($text)
    {
        if (!is_string($text)) {
            throw new TV_Text_Exception(__METHOD__.' requires string as argument, got '.gettype($text));
        }
        $text  = $this->cleanText($text);
        $count = count(explode(" ", $text));

        return $count;

    }

    /**
     * Clean up text from punctuation and non-alphabetic symbols
     *
     * @param string $text
     *
     * @return string
     */
    public function cleanText($text)
    {
        $text          = trim($text);
        $text          = html_entity_decode($text);
        $stripTags     = new Zend_Filter_StripTags();
        $text          = $stripTags->filter($text);
        $text          = str_replace(array(',', '.', "\r\n", "\n", "\r"), ' ', $text);
        $text          = preg_replace("/\s\s+/", " ", $text);
        $stripTheRest  = new Zend_Filter_Alnum(true);
        $text          = $stripTheRest->filter($text);
        $text          = str_replace('8217', "'", $text);
        //$text          = str_replace($this->_shortWords, $this->_longWords, $text);
        $text          = strtolower($text);
        return $text;
    }
    
    /**
     * Cleans up text from non-alphabetic symbols. Leaves punctuation
     *
     * @param string $text
     *
     * @return string
     */
    public function cleanTextPunc($text)
    {
        $text          = trim($text);
        $text          = html_entity_decode($text);
        $stripTags     = new Zend_Filter_StripTags();
        $text          = $stripTags->filter($text);
        $text          = str_replace(array("\r\n", "\n", "\r"), ' ', $text);
        $text          = preg_replace("/\s\s+/", " ", $text);
        $text          = str_replace(array(',', '.'), array('COMA', 'DOT'), $text);
        $stripTheRest  = new Zend_Filter_Alnum(true);
        $text          = $stripTheRest->filter($text);
        $text          = str_replace(array('COMA', 'DOT'), array(',', '.'), $text);
        $text          = str_replace('8217', "'", $text);
        return $text;
    }
    
    /**
     * Returns array of words from the text in alphabetic order and removed duplicates
     *
     * @param string $text
     *
     * @return array
     * @throws TV_Text_Exception if $text is not string
     */
    public function getWords($text)
    {
        if (!is_string($text)) {
            throw new TV_Text_Exception(__METHOD__.' requires string as argument, got '.gettype($text));
        }
        
        $text       = $this->cleanText($text);
        $wordsArray = explode(" ", $text);
        $wordsArray = array_unique($wordsArray);
        sort($wordsArray, SORT_STRING);
        return $wordsArray;
            
    }
    
    /**
     * Returns associative array with words frequency within the given text
     *
     * @param string $text
     *
     * @return array
     * @throws TV_Text_Exception if $text is not string
     */
    public function getWordsStat($text)
    {
        if (!is_string($text)) {
            throw new TV_Text_Exception(__METHOD__.' requires string as argument, got '.gettype($text));
        }
        
        $text      = $this->cleanText($text);
        $frequency = array_count_values(str_word_count($text,1));
        arsort($frequency);
        return $frequency;
    }
    
    /**
     * Returns array of phrases for given text
     *
     * @param string $text
     * @param int    $wordsNumber
     *
     * @return array
     * @throws TV_Text_Exception If $text is not string
     * @throws TV_Text_Exception If $wordsNumber is not int
     */
    public function getPhrases($text, $wordsNumber)
    {
        if (!is_string($text)) {
            throw new TV_Text_Exception(__METHOD__.' requires string as argument, got '.gettype($text));
        }
        if (!is_int($wordsNumber)) {
            throw new TV_Text_Exception(__METHOD__.' requires int as argument, got '.gettype($text));
        }
        
        $text = $this->cleanTextPunc($text);
        
        $sentences = explode('.', $text);
        $sentences = $this->_deleteNullValues($sentences);
        $phrases   = array();
        foreach($sentences as $sentence) {
            $phrases = array_merge($phrases, $this->analyzeSentence($sentence, $wordsNumber));
        }
        $phrases = array_unique($phrases);
        return $phrases;
    }
    
    /**
     * Return statistics for phrases
     *
     * @param string $text        Text to be analyzed
     * @param string $wordsNumber Number of words in phrase
     *
     * @return array
     * @throws TV_Text_Exception If $text is not string
     * @throws TV_Text_Exception If $wordsNumber is not integer
     */
    public function getPhrasesStat($text, $wordsNumber)
    {
        if (!is_string($text)) {
            throw new TV_Text_Exception(__METHOD__.' requires string as argument, got '.gettype($text));
        }
        if (!is_int($wordsNumber)) {
            throw new TV_Text_Exception(__METHOD__.' requires int as argument, got '.gettype($text));
        }
        
        $phrases = $this->getPhrases($text, $wordsNumber);
        $stats   = array();
        $matches = array();
        foreach($phrases as $phrase) {
            $stats[strtolower($phrase)] = preg_match_all("/\b$phrase\b/i", $text, $matches);
        }
        
        return $stats;
    }
    
    
    /**
     * Extracts from the sentence all phrases consisting of $wordsNumber words
     *
     * @param string  $sentence    Sentence to analyze
     * @param int     $wordsNumber Number of words in phrase
     * @param boolean $ignoreComa  (false by default) if there is at least one coma the phrase will be ignored
     *
     * @return array
     */
    public function analyzeSentence($sentence, $wordsNumber, $ignoreComa = false)
    {
        
        $words_old = explode(' ', $sentence);
        
        /*foreach($words_old as $key => $value) {
            if($value == "") {
                unset($array[$key]);
            }
        }
        $words = array_values($words_old);
        */
        $words = $this->_deleteNullValues($words_old);
        
        $phrases = array();
        $count = count($words)-($wordsNumber-1);
        
        for ($i=0;$i<$count;$i++) {
            /**
             * @todo Refactor this part. It's total crap
             */
            if ($wordsNumber == 2) {
                $phrases[$i] = $words[$i].' '.$words[$i+1];
            }
            
            if ($wordsNumber == 3) {
                $phrases[$i] = $words[$i].' '.$words[$i+1].' '.$words[$i+2];
            }
            
            if ($wordsNumber == 4) {
                $phrases[$i] = $words[$i].' '.$words[$i+1].' '
                              .$words[$i+2].' '.$words[$i+3];
            }
            
            if ($wordsNumber == 5) {
                $phrases[$i] = $words[$i].' '.$words[$i+1].' '.$words[$i+2].' '
                              .$words[$i+3].' '.$words[$i+4];
            }
            
            $removed = false;
                    
            // If there is a coma?
            if (preg_match('/,/',$phrases[$i]) && !$ignoreComa) {
                $removed = true;
            }
            
            // If come in the end of the phrase - phrase is ok
            if (preg_match('/,$/',$phrases[$i]) && !$ignoreComa) {
                $removed = false;
            }
            
            // If there are more than two comas - remove phrase
            if (preg_match('/,.*,$/',$phrases[$i]) && !$ignoreComa) {
                $removed = true;
            }
            
            if ($removed == true) {
                array_pop($phrases);
            } else {
                $phrases[$i] = $this->_removePunctuation($phrases[$i]);
            }
        }
        
        $phrases_new = array_values($phrases);
        return $phrases_new;
    }
    
    private function _deleteNullValues($array)
    {
        foreach($array as $key => $value) {
            if($value == "") {
                unset($array[$key]);
            }
        }
        
        return array_values($array);
    }
    
    private function _removePunctuation($text)
    {
        $text = trim(str_replace(array(',','.',"\r\n", "\n", "\r"), '', $text));
        return $text;
    }
    
    /**
     * Returns number of syllables in the text
     *
     * @param string $text
     *
     * @return int
     * @throws TV_Text_Exception if $text is not string
     */
    public function syllablesCount($text) {
        if (!is_string($text)) {
            throw new TV_Text_Exception(__METHOD__.' requires string as argument, got '.gettype($text));
        }

        $text = new Text_Word($text);
        return $text->numSyllables();
    }


}